/*************************************************************************
> File Name: tftp-client.c
> Author: hzy
> Created Time: 2023-09-19 15:19:51
> Description:
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket");
        exit(-1);
    }

    // 发送连接请求
    char send_buf[512] = {};
    sprintf(send_buf, "%c%c%s%c%s%c", 0x00, 0x01, argv[1], 0x00, "octet", 0x00);

    // 填充服务器ip地址信息
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(69);
    server_addr.sin_addr.s_addr = inet_addr("10.7.178.94");

    int send_ret = sendto(sockfd,
                          send_buf,
                          sizeof(send_buf),
                          0,
                          (struct sockaddr *)&server_addr,
                          sizeof(server_addr));
    if (send_ret < 0)
    {
        perror("sendto");
        exit(-1);
    }

    int filefd = open(argv[1], O_CREAT | O_RDWR, 0666);
    if (filefd < 0)
    {
        perror("open");
        return -1;
    }

    // 接受数据包
    char recv_buf[516] = {};
    char ack_buf[5] = {};
    struct sockaddr_in temp_addr;
    socklen_t addr_len = sizeof(temp_addr);

    int recv_end = 0;
    while (1)
    {
        memset(recv_buf, 0, sizeof(recv_buf));
        // 接受数据
        int recv_len = recvfrom(sockfd,
                                recv_buf,
                                sizeof(recv_buf),
                                0,
                                (struct sockaddr *)&temp_addr,
                                &addr_len);
        if (recv_len < 512 + 4)
        {
            // 发送到最后一个数据包
            recv_end = 1;
        }

        // 将收到的文件数据内容写入打开的文件
        write(filefd, recv_buf + 4, recv_len - 4);

        // ACK信号
        int len2 = sprintf(ack_buf, "%c%c%c%c", 0x00, 0x04, recv_buf[2], recv_buf[3]);
        int send_ret2 = sendto(sockfd,
                               ack_buf,
                               len2,
                               0,
                               (struct sockaddr *)&temp_addr,
                               addr_len);
        if (send_ret2 < 0)
        {
            perror("sendto2");
            exit(-1);
        }
        if (recv_end == 1)
        {
            break;
        }
    }

    close(sockfd);
    close(filefd);

    return 0;
}